import axios from 'axios';
import { getAuthorToken } from '@/utils/author';
import { refreshToken } from '@/api/userApi.js';
import { userStore } from '@/store/index.js';
/**
 * axios二次封装
 * @param {Object} axiosConfig axios配置
 * @param {Object} customOptions 个性化配置
 * @param {Object} customMsg   自定义消息对象
 * @returns promise对象
 */
function myAxios(axiosConfig, customOptions, customMsg = {}) {
    // 创建axios实例
    const service = axios.create({
        baseURL: 'http://localhost:3300/api', // 设置统一的请求前缀
        timeout: 10000, // 设置统一的超时时长
        // proxy: {
        //     host: '159.75.73.211', // 代理服务器的主机名或 IP 地址
        //     port: 4333, // 代理服务器的端口号
        // },
    });

    // 自定义axios属性
    service.defaults.retryMax = 4; // 最大重试次数
    service.defaults.__retryCount = 0; // 重试轮数
    service.defaults.retryDelay = 800; // 重试间隔

    // 自定义配置
    // assign用于合并两个对象
    // 如果有相同属性,就覆盖值
    // 没有相同属性，就添加属性和值
    let custom_options = Object.assign(
        {
            reduct_data_format: true, // 是否开启简洁的数据结构响应, 默认为true
            default_err_msg: false, // 是否开启接口统一错误信息响应,默认为true
            // code_msg_show: false, // 是否开启code不为0时的信息提示, 默认为false
            server_err_msg: false, //是否开启服务端返回错误信息显示
            custom_msg: false, // 是否开启自定义消息
        },
        customOptions
    );

    // 请求拦截
    service.interceptors.request.use(
        config => {
            // 请求头自动携带token
            if (getAuthorToken() && typeof window !== 'undefined') {
                config.headers.Authorization = getAuthorToken();
            }
            return config;
        },
        error => {
            return Promise.reject(error);
        }
    );

    //

    service.interceptors.response.use(
        // 请求成功信息(接收到接口响应的信息)
        response => {
            // 请求成功：前端自定义信息提示(可选)
            if (Object.keys(customMsg).length !== 0) {
                showMesgBox('success', customMsg);
            }

            // 请求成功后返回信息
            return custom_options.reduct_data_format ? response.data : response; // 简洁数据结构响应
        },

        // 请求出错
        async error => {
            console.log('请求出错');
            console.log(error);
            if (error.response?.status === 403 && error.response.config.url !== '/auth/refreshlogin') {
                return errorRetry(error);
            } else {
                custom_options.default_err_msg && httpErrorStatusHandle(error);
                custom_options.server_err_msg && serverErrorMsg(error);
                if (Object.keys(customMsg).length !== 0) {
                    showMesgBox('error', customMsg);
                }
                return Promise.reject(error);
            }
        }
    );
    // 将请求配置传递给axios实例，并返回promise对象
    return service(axiosConfig);
}

export default myAxios;

//#region 已完成方法
/**
 * @description：异常处理[功能]
 * @param {*} error promise rejected
 */
function httpErrorStatusHandle(error) {
    let message = '';
    if (error && error.response) {
        switch (error.response.status) {
            case 302:
                message = '接口重定向';
                break;
            case 400:
                message = '参数不正确';
                break;
            case 401:
                message = '您未登录，或者登录已经超时，请先登录！';
                break;
            case 403:
                message = '您没有权限操作';
                break;
            case 404:
                message = `请求地址出错: ${error.response.config.url}`;
                break; // 在正确域名下
            case 408:
                message = '请求超时';
                break;
            case 409:
                message = '系统已存在相同数据';
                break;
            case 500:
                message = '服务器内部错误';
                break;
            case 501:
                message = '服务未实现';
                break;
            case 502:
                message = '服务器网关错误';
                break;
            case 503:
                message = '服务不可用';
                break;
            case 504:
                message = '服务暂时无法访问，请稍后再试';
                break;
            case 505:
                message = 'HTTP版本不受支持';
                break;
            case 'ECONNABORTED':
                message = '请求超时';
                break;
            default:
                message = '异常问题，请联系管理员！';
                break;
        }
    }
    if (error.message.includes('timeout')) message = '网络请求超时,请检查网络环境';
    if (error.message.includes('Network')) message = window.navigator.onLine ? '服务端异常！' : '您断网了！';

    ElMessage({
        type: 'error',
        message,
    });
}

/**
 * @description:显示服务端响应的错误信息
 * @param {*} error promise rejected
 */
function serverErrorMsg(error) {
    let resp = error.response.data;
    // || Object.keys(resp).length !== 0
    if (resp !== 'undefined') {
        ElMessage({
            type: 'error',
            message: resp.err.msg,
        });
    }
}

/**
 * @description: 显示自定义消息
 * @param {*} mode 显示模式 error/success
 * @param {*} msgObj
 * @return {*}
 */
function showMesgBox(mode, msgObj) {
    if (msgObj.hasOwnProperty(mode) || mode === msgObj.mode) {
        ElMessage({
            type: msgObj.mode,
            message: msgObj.msg,
        });
    }
}
//#endregion

/**
 * @description: 请求出错重试
 * @param {*} error
 * @return {*}
 */
function errorRetry(error) {
    let config = error.config;
    // 重试次数自增
    config.__retryCount = config.__retryCount || 0;
    config.__retryCount++;
    console.log('重试次数:' + config.__retryCount);
    if (config.__retryCount >= config.retryMax) {
        console.log('重试次数超限');
        return Promise.reject(error);
    } else {
        const delay = new Promise(resolve => setTimeout(resolve, config.retryDelay));

        switch (config.__retryCount) {
            case 1:
                return delay.then(() => myAxios(config));
            case 2:
                return refreshToken()
                    .then(() => delay)
                    .then(() => myAxios(config));
            case 3:
                ElMessage({
                    type: 'error',
                    message: '登录过期，请重新登录',
                });
                userStore.isLogin = false;

                // router.push({ path: '/login' });
                return Promise.reject(error);
            default:
                return Promise.reject(error);
        }
    }
}
